/*
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Description:
 *   Handles user input.
 */

#include "x_keys.h"
#include "x_main.h"
#include "x_saves.h"
#include "doomstat.h"
#include "d_event.h"
#include "e6y.h"
#include "hu_stuff.h"
#include "st_stuff.h"

static int turnstep = 1;

void x_run(signed char val)
{
    // no 0x80
    if (val == -128)
        val = -127;
    tics[displayplayer][current_tic].forwardmove = val;
    x_goBack(0);
    x_display();
}

void x_strafe(signed char val)
{
    tics[displayplayer][current_tic].sidemove = val;
    x_goBack(0);
    x_display();
}

void x_turn(signed short val)
{
    tics[displayplayer][current_tic].angleturn = val << (!longtics * 8);
    x_goBack(0);
    x_display();
}

void x_toggleFire(void)
{
    if (tics[displayplayer][current_tic].buttons & BT_SPECIAL)
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons ^= BT_ATTACK;
    x_goBack(0);
    x_display();
}

void x_toggleUse(void)
{
    if (tics[displayplayer][current_tic].buttons & BT_SPECIAL)
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons ^= BT_USE;
    x_goBack(0);
    x_display();
}

void x_changeWeapon(char wpn)
{
    if (tics[displayplayer][current_tic].buttons & BT_SPECIAL)
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons &= ~(BT_CHANGE | BT_WEAPONMASK);
    if (!(wpn < 1 || wpn > 9))
        tics[displayplayer][current_tic].buttons |=
          (BT_CHANGE | (--wpn << BT_WEAPONSHIFT));
    x_goBack(0);
    x_display();
}

void x_togglePause(void)
{
    if (!(tics[displayplayer][current_tic].buttons & BT_SPECIAL))
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons ^= BT_SPECIAL | BTS_PAUSE;
    x_goBack(0);
    x_display();
}

void x_changeSaveGame(char slot)
{
    if (!(tics[displayplayer][current_tic].buttons & BT_SPECIAL))
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons &=
      ~(BT_SPECIAL | BTS_SAVEGAME | BTS_SAVEMASK);
    if (!(slot < 1 || slot > 8))
        tics[displayplayer][current_tic].buttons |=
          (BT_SPECIAL | BTS_SAVEGAME | (--slot << BTS_SAVESHIFT));
    x_goBack(0);
    x_display();
}

void x_changeLoadGame(char slot)
{
    if (!(tics[displayplayer][current_tic].buttons & BT_SPECIAL))
        tics[displayplayer][current_tic].buttons = 0;
    tics[displayplayer][current_tic].buttons &= ~(BT_SPECIAL | BTS_SAVEMASK);
    if (!(slot < 1 || slot > 8))
        tics[displayplayer][current_tic].buttons |=
          (BT_SPECIAL | (--slot << BTS_SAVESHIFT));
    x_goBack(0);
    x_display();
}

void x_seekDemo(int numtics)
{
    if (numtics < 0)
        x_goBack(-numtics);
    else
        x_goForward(numtics);
    x_display();
}

void x_copyTic(void)
{
    x_moveTics(1);
    tics[displayplayer][current_tic + 1] = tics[displayplayer][current_tic];
    ++tic_len[displayplayer];
    x_goForward(1);
    x_display();
}

void x_copyTicX(int val)
{
    int i;
    ticcmd_t tic = tics[displayplayer][current_tic];
    if (val < 1)
        return;
    x_moveTics(val);
    for (i = 1; i <= val; i++)
        tics[displayplayer][current_tic + i] = tic;
    tic_len[displayplayer] += val;
    x_goForward(val);
    x_display();
}

void x_deleteTic(void)
{
    if (!tic_len[displayplayer])
        return;
    x_moveTics(-1);
    --tic_len[displayplayer];
    x_goBack(0);
    x_display();
}

void x_deleteTicX(int val)
{
    if (val < 1)
        return;
    val = tic_len[displayplayer] - val < 1
      ? tic_len[displayplayer] : val;
    x_moveTics(-val);
    tic_len[displayplayer] -= val;
    x_goBack(0);
    x_display();
}

void x_newTic(void)
{
    ticcmd_t nulltic = {0};
    x_moveTics(1);
    tics[displayplayer][current_tic + 1] = nulltic;
    ++tic_len[displayplayer];
    x_goForward(1);
    x_display();
}

void x_changePlayerView(int p)
{
    if (--p < 0 || p > 3 || !playeringame[p] || displayplayer == p
      || gamestate != GS_LEVEL)
        return;
    displayplayer = p;

    ST_Start();
    HU_Start();
    x_display();
}

void x_toggleBlood(void)
{
    palette_onbonus = palette_ondamage = palette_onpowers ^= 1;

    ST_Start();
    HU_Start();
    x_display();
}

static void x_transpose(char mode, char direction)
{
    signed char forwardmove, sidemove;
    signed short angleturn;
    if (mode < 0 || mode > 2)
        return;
    sidemove = tics[displayplayer][current_tic].sidemove * direction;
    forwardmove = -tics[displayplayer][current_tic].forwardmove * direction;
    angleturn = (-64 * direction) << 8;
    if (mode != 1) {
        tics[displayplayer][current_tic].forwardmove = sidemove;
        tics[displayplayer][current_tic].sidemove = forwardmove;
    }
    if (mode != 2)
        tics[displayplayer][current_tic].angleturn += angleturn;
    x_goBack(0);
    x_display();
}

void x_transposeLeft(char mode)
{
    x_transpose(mode, -1);
}

void x_transposeRight(char mode)
{
    x_transpose(mode, 1);
}

void x_setTurnStep(int val)
{
    turnstep = val;
}

void x_turnStep(char direction)
{
    tics[displayplayer][current_tic].angleturn
      += (direction * turnstep) << (!longtics * 8);
    x_goBack(0);
    x_display();
}

void x_setSavepoint(void)
{
    if (!x_makeSavepoint(true)) {
        x_goForward(1);
        x_display();
    }
}

void x_unsetSavepoint(void)
{
    x_clearUserSavepoint();
    if (savepoint_style == SP_AUTO)
        savepoint_style = SP_START;
    x_goBack(0);
    x_display();
}

void x_setSavepointStyle(int style)
{
    if (savepoint_style == style || style < SP_NOSAVE || style > SP_AUTO)
        return;
    savepoint_style = style;
    if (savepoint_style == SP_USER)
        x_clearMapSavepoints();
}

